
package de.fuberlin.inf.alp2;

import javax.activity.InvalidActivityException;
import de.fuberlin.inf.alp2.utils.*;

/**
 * This class has been implemented within the scope of the second exercise of
 * the lecture <i>"Algorithmen und Programmierung 2 - Objektorientierte
 * Programmierung"</i>.
 * @author stefanr
 */
public class SieveOfEratosthenes {
	
	/**
	 * @param args (If first argument contains an integer, it will be used as
	 * max. Otherwise the program will ask you to type in the value again.
	 */
	public static void main(String[] args) {
		try {
			Timer timer = new Timer();
			final int MAX;
			int nrOfPrimes = 0;
			MAX = SieveOfEratosthenes.getMaxValue(args);
			timer.start();
			boolean[] isNoPrime = SieveOfEratosthenes.getIsNoPrime(MAX);
			timer.stop();
			int len = isNoPrime.length;
			for (int i = 0; i < len; i++)
				if (!isNoPrime[i])
				{
					nrOfPrimes++;
					System.out.print(i + " ");
				}
			System.out.println("\n(There are " + nrOfPrimes + " primes less " +
					"or equal to " + MAX + ")");
			System.out.println(timer);
		}
		catch (InvalidActivityException exc){}
	} // main
	
	
	/**
	 * I decided to implement a method, that delivers an array of booleans the
	 * other way around. So if the index is a prime number, the value at the
	 * index will be false. If the index has divisors different to 1 and to
	 * itself, the value at the index will be true. The reason behind is, that
	 * Java initializes an array of boolean with values 'false' and I wanted to
	 * spare an extra loop passage.
	 * @param MAX (The upper limit of primes).
	 * @return Array of booleans where true means, that the index has divisors
	 * different to 1 and to itself
	 */
	private static boolean[] getIsNoPrime(final int MAX) {
		boolean[] isNoPrime = new boolean[MAX + 1];
		
		// strike out 0 and 1
		isNoPrime[0] = true;
		isNoPrime[1] = true;
		for (int i = 2; i <= Math.sqrt(MAX + 1) ; i++)
			if (!isNoPrime[i]) // if not striked out, i is prime
				for (int j = i; (i * j) <= MAX; j++)
					isNoPrime[i*j] = true; // strike out multiples of i
		
		return isNoPrime;
	} // getIsNoPrime

	/**
	 * This method will use the first parameter to convert it to int. If this is
	 * not possible, it requests an input by the user, until the entered string
	 * has been successfully converted to int.
	 * @param args If first argument contains an integer, it will be used as
	 * max. Otherwise the program will ask to type in the value again.
	 * @return The int value of the passed string.
	 */
	private static int getMaxValue(String[] args) {
		int max = 0;
		
		if (args.length > 0) {
			// If the max value is passed with the program arguments, take it
			try {
				max = Integer.parseInt(args[0]);
			}
			catch (NumberFormatException exc) { }
		} // args.length > 0
		while (max < 1)
			max = ConsoleInput.readInt("Please enter the MAX value (integer " +
					"greater then zero)", "The entered value could not be " +
					"converted to int.");
		
		return max;
	} // getMaxValue
} // class
